import { defineComponent, ref, watch } from 'vue';
import { isEqual, cloneDeep } from 'lodash-es';
import PropTypes from '../types';
import { withInstall } from '@/components/utils';
import AddConditionButton from './AddConditionButton';
import ConditionGroupItem from './ConditionGroupItem';
import './style/index.less';
const ConditionGroupProps = {
    // 空的表达式数据
    expression: PropTypes.object.def({
        filterType: 'CONDITION',
        filterCondition: {
            filterColumnName: '',
            type: '',
            conditionType: '',
            dateFormat: 'yyyy-MM-dd',
            value: null,
        },
    }),
    // 数据
    modelValue: PropTypes.object,
};
const ConditionGroup = defineComponent({
    name: 'ConditionGroup',
    props: ConditionGroupProps,
    emits: ['update:modelValue'],
    setup(props, { emit, slots, expose }) {
        // ------------------------------- 属性
        const key = ref(0);
        // 数据源
        const conditionData = ref({});
        // 当前选中
        const selectedCondition = ref(null);
        // 当前选中父级
        const selectedParentCondition = ref(null);
        // ------------------------------- 元素节点
        const buttonDefaultSolts = slots.buttonGroup
            ? slots.buttonGroup
            : () => (<div class="condition-button-group">
            <AddConditionButton buttonType="条件" class="condition-button" onClick={handleAddCondition}/>
            <AddConditionButton buttonType="公式" class="condition-button" onClick={handleAddFormula}/>
          </div>);
        // ------------------------------ 监听
        watch(() => props.modelValue, dealDataSource, {
            deep: true,
            immediate: true,
        });
        // ----------------------------- 交互
        // 条件表达式发生变化时，向组件外抛出事件
        function handleConditionDataChange() {
            emit('update:modelValue', conditionData.value);
        }
        /**
         * 添加表达式节点的方法
         * 注：自定义操作按钮时，可以在组件外调用该方法添加新的表达式节点
         * @param {String} operator 逻辑运算符的枚举值：AND/OR
         * @param {Object} customExpression 空表达式节点的对象，该参数缺省时使用props传进来的expression属性
         */
        function handleAddCondition(operator, customExpression) {
            const newExpressionNode = generateExpressionNode(customExpression || props.expression);
            // 如果根节点改没有初始化，则初始化根节点
            const { children } = conditionData.value || {};
            if (!children || !children.length) {
                conditionData.value = {
                    operator,
                    key: key.value++,
                    children: [newExpressionNode],
                };
                handleConditionDataChange();
                return;
            }
            // 如果当前节点不存在父节点，则当前节点为根节点
            if (!selectedParentCondition.value || !Object.keys(selectedParentCondition.value).length) {
                /*
                 * 如果新添加的逻辑运算符与跟节点的一致，则直接将新增的表达式节点增加到跟节点的子表达式列表中
                 * 否则将新增的表达式节点和根节点，使用新添加的逻辑运算符合并成一个表达式作为跟节点
                 */
                if (conditionData.value?.operator === operator) {
                    conditionData.value?.children?.push(newExpressionNode);
                }
                else {
                    conditionData.value = mergeCondition(conditionData.value, newExpressionNode, operator);
                }
            }
            else {
                // 获取当前表达式在父节点表达式列表中的下标
                const index = selectedParentCondition.value?.children?.findIndex((item) => item === selectedCondition.value);
                /*
                 * 如果新添加的逻辑运算符与父节点的一致，则给父节点的子表达式列表中、当前表达式的后面插入新的表达式节点
                 * 否则将新增的表达式节点和当前节点的表达式，使用新添加的逻辑运算符合并成一个表达式，并替换当前节点的表达式
                 */
                if (selectedParentCondition.value.operator === operator) {
                    selectedParentCondition.value?.children?.splice(index + 1, 0, newExpressionNode);
                }
                else {
                    const newCondition = mergeCondition(selectedCondition.value, newExpressionNode, operator);
                    selectedParentCondition.value?.children?.splice(index, 1, newCondition);
                }
            }
            // 清空选中的节点
            selectedCondition.value = null;
            selectedParentCondition.value = null;
            handleConditionDataChange();
        }
        // 公式点击事件
        function handleAddFormula(_operator) { }
        // 生成一个表达式节点（条件表达式树的叶子节点）
        function generateExpressionNode(expression) {
            return {
                expression: cloneDeep(expression),
                key: key.value++,
            };
        }
        // 将两个表达式节点合并成一个节点
        function mergeCondition(condition1, condition2, operator) {
            return {
                operator,
                key: key.value++,
                children: [condition1, condition2],
            };
        }
        // 数据源改变通知
        function dealDataSource() {
            // 如果value的值与conditionData的值一致，则不需要初始化
            if (isEqual(conditionData.value, props.modelValue)) {
                return;
            }
            // 如果value的值不是一个树状数据，则清空条件数据
            if (!props.modelValue || !props.modelValue.children) {
                conditionData.value = {};
                return;
            }
            // 初始化传入的数据
            conditionData.value = initTreeNodeKey(cloneDeep(props.modelValue));
            // 更新完conditionData后，抛出数据变化的事件，保证组件内外的conditionData使用同一个对象，以便可以通过作用域插槽修改数据
            handleConditionDataChange();
        }
        /**
         * 选中一个条件表达式节点，
         * 注：自定义选中表达式节点的方式时，可以在组件外调用该方法
         * @param {Object} currentCondition 当前表达式的树节点
         * @param {Object} parentCondition 当前表达式节点的父节点
         */
        function handleSelectCondition(currentCondition, parentCondition) {
            // 如果当前选择的节点与之前选中的节点一样，则清除选中的节点；否则缓存当前选择的节点
            if (selectedCondition.value === currentCondition) {
                selectedCondition.value = null;
                selectedParentCondition.value = null;
            }
            else {
                selectedCondition.value = currentCondition;
                selectedParentCondition.value = parentCondition;
            }
        }
        // 删除条件表达式节点
        function handleDeleteCondition(currentCondition, parentCondition) {
            // 删除当前节点
            const deleteIndex = parentCondition.children.findIndex((item) => item === currentCondition);
            parentCondition.children.splice(deleteIndex, 1);
            // 如果删除当前节点后，其父节点没有了子节点，则清理一次树中的空节点
            if (parentCondition.children.length === 0) {
                conditionData.value = trimConditionTree(conditionData.value);
            }
            // 清空已选中的节点
            selectedCondition.value = null;
            selectedParentCondition.value = null;
            handleConditionDataChange();
        }
        // 处理条件格式插槽
        function handleDealExpressionSlots(soltsData) {
            return slots.expressionSolt && slots.expressionSolt(soltsData);
        }
        // 删除表达式树中的空节点
        function trimConditionTree(conditionTree) {
            const { expression, children } = conditionTree;
            // 如果是叶子节点，则直接返回
            if (expression || !children) {
                return conditionTree;
            }
            // 递归删除子节点中的空子节点
            children.forEach((treeNode) => {
                trimConditionTree(treeNode);
            });
            // 过滤当前节点的子节点，只保留叶子节点及子节点不是空数组的节点
            conditionTree.children = children.filter((treeNode) => treeNode.expression || (treeNode.children && treeNode.children.length));
            return conditionTree;
        }
        // 初始化树节点的key
        function initTreeNodeKey(treeData) {
            treeData.key = key.value++;
            // 如果当前节点存在子节点，则给所有子节点初始化key
            if (treeData.children && treeData.children.length) {
                treeData.children.forEach((treeNode) => {
                    initTreeNodeKey(treeNode);
                });
            }
            return treeData;
        }
        // 暴露给组件外，可供父组件使用ref调用的方法
        expose({
            handleAddCondition,
            handleSelectCondition,
        });
        return () => (<div class="condition-group-wrapper">
        {/*按钮部分*/}
        {buttonDefaultSolts()}
        {/*条件表达式组 */}
        {conditionData.value?.children?.length > 0 && (<ConditionGroupItem class="condition-group" condition-data={conditionData.value} selected-condition={selectedCondition.value} onSelectCondition={handleSelectCondition} onDeleteCondition={handleDeleteCondition} v-slots={{ expressionSolt: (props) => handleDealExpressionSlots(props) }}/>)}
      </div>);
    },
});
export default withInstall(ConditionGroup);
//# sourceMappingURL=index.jsx.map